pub mod postgresql;
pub mod redis;

use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
use uuid::Uuid;

#[async_trait]
pub trait Storage: Send + Sync {
    // 节点管理
    async fn register_node(&self, node: &NodeInfo) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
    async fn unregister_node(&self, node_id: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
    async fn get_node(&self, node_id: &str) -> Result<Option<NodeInfo>, Box<dyn std::error::Error + Send + Sync>>;
    async fn get_all_nodes(&self) -> Result<Vec<NodeInfo>, Box<dyn std::error::Error + Send + Sync>>;
    async fn update_node_status(&self, node_id: &str, status: NodeStatus) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
    async fn update_node_heartbeat(&self, node_id: &str, timestamp: chrono::DateTime<chrono::Utc>) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
    
    // 分组管理
    async fn create_group(&self, group: &Group) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
    async fn get_group(&self, group_id: &str) -> Result<Option<Group>, Box<dyn std::error::Error + Send + Sync>>;
    async fn get_all_groups(&self) -> Result<Vec<Group>, Box<dyn std::error::Error + Send + Sync>>;
    async fn update_group(&self, group: &Group) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
    async fn delete_group(&self, group_id: &str) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
    
    // 命令管理
    async fn store_command(&self, command: &CommandRecord) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
    async fn get_command(&self, command_id: &str) -> Result<Option<CommandRecord>, Box<dyn std::error::Error + Send + Sync>>;
    async fn update_command_status(&self, command_id: &str, status: CommandStatus) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
    
    // 文件管理
    async fn store_file_metadata(&self, metadata: &FileMetadata) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
    async fn get_file_metadata(&self, file_id: &str) -> Result<Option<FileMetadata>, Box<dyn std::error::Error + Send + Sync>>;
    async fn update_file_status(&self, file_id: &str, status: FileStatus) -> Result<(), Box<dyn std::error::Error + Send + Sync>>;
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeInfo {
    pub id: String,
    pub hostname: String,
    pub ip_address: String,
    pub tags: Vec<String>,
    pub status: NodeStatus,
    pub last_heartbeat: DateTime<Utc>,
    pub capabilities: Vec<String>,
    pub metadata: std::collections::HashMap<String, String>,
    pub group_ids: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum NodeStatus {
    Online,
    Offline,
    Maintenance,
    Error,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Group {
    pub id: String,
    pub name: String,
    pub description: String,
    pub selector: GroupSelector,
    pub nodes: Vec<String>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum GroupSelector {
    AllNodes,
    ByTags(Vec<String>),
    ByCapabilities(Vec<String>),
    CustomSelector {
        expression: String,
        metadata: std::collections::HashMap<String, String>,
    },
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommandRecord {
    pub id: String,
    pub command_type: CommandType,
    pub target: String,
    pub payload: serde_json::Value,
    pub status: CommandStatus,
    pub created_at: DateTime<Utc>,
    pub completed_at: Option<DateTime<Utc>>,
    pub results: Vec<CommandResult>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CommandType {
    Shell,
    Script,
    ServiceRestart,
    FileOperation,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CommandStatus {
    Pending,
    Running,
    Completed,
    Failed,
    Cancelled,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommandResult {
    pub node_id: String,
    pub success: bool,
    pub exit_code: i32,
    pub stdout: String,
    pub stderr: String,
    pub execution_time: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileMetadata {
    pub id: String,
    pub filename: String,
    pub file_size: u64,
    pub checksum: String,
    pub status: FileStatus,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum FileStatus {
    Pending,
    Transferring,
    Completed,
    Failed,
} 